<?php

namespace App\Kuafu\Product\Model;

use App\Kuafu\Base\Enum\BaseCodeEnum;
use App\Kuafu\Base\Enum\ClientEnum;
use App\Kuafu\Base\Model\Traits\KfSoftDeletes;
use App\Kuafu\Base\Model\Traits\KfUid;
use App\Kuafu\Category\Model\CategoryModel;
use App\Kuafu\Product\Enum\CodeEnum;
use App\Kuafu\Product\Enum\CodeEnum as ProductCode;
use App\Kuafu\Product\Enum\ProductCacheEnum;
use App\Kuafu\Product\Enum\ProductCodeEnum;
use App\Kuafu\Product\Exceptions\ProductException;
use App\Kuafu\Product\Service\ProductShopService;
use App\Kuafu\ProductMenu\Service\ProductMenuService;
use App\Kuafu\Shop\Model\ShopProductStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Kuafu\Base\Enum\DBEnum;
use App\Kuafu\Base\Model\BaseModel;

class Product extends BaseModel
{
    use HasFactory, KfSoftDeletes, KfUid;

    protected $fillable    = [
        'id',
        'name',
        'categoryId',
        'desc',
        'imageUrl',
        'price',
        'sort',
        'createdAt',
        'createdByUid',
        'updatedAt',
        'updatedByuid',
        'status',
        'isHot',
        'isRecommend',
        'menuId',
        'vipPrice',
        "costPrice",
        'unit',
        'brandId',
        'type',
        'showPlatform',
        'isDeleted',
        'status'
    ];

    /**
     * 字面对应描述文本
     */
    const FIELDS_TEXT = [
        "name"         => "菜品名称",
        "desc"         => "菜品描述",
        "price"        => "菜品价格",
        "costPrice"    => "成本价",
        "vipPrice"     => "会员价",
        "isHot"        => "是否热门",
        "isRecommend"  => "是否推荐",
        "showPlatform" => "展示平台",
    ];

    protected $modelCached = true;

    public function categoryRel()
    {
        return $this->belongsTo(CategoryModel::class, 'categoryId');
    }

    /**
     * 添加产品
     * @param $data
     * @throws ProductException
     */
    public static function addProduct($data)
    {
        try {
            return Product::query()->create($data);
        } catch (\Exception $exception) {
            throw new ProductException(ProductCodeEnum::ERR_PRODUCT_INSERT, '', $exception);
        }
    }

    /**
     * 根据menuId、id更新
     * @param int $menuId
     * @param int $productId
     * @throws ProductException
     */
    public static function setProductByMenuIdPid(int $menuId, int $productId, array $data)
    {
        try {
            $obj = Product::query()->withoutGlobalScope('isDel')
                          ->where(['id' => $productId, 'menuId' => $menuId])
                          ->first();

            if ($obj) {
                Product::query()->withoutGlobalScope('isDel')
                       ->where(['id' => $productId, 'menuId' => $menuId])->update($data);
            } else {
                $data['id']     = $productId;
                $data['menuId'] = $menuId;
                Product::query()->create($data);
            }

        } catch (\Exception $e) {
            throw new ProductException(ProductCodeEnum::ERR_PRODUCT_UPDATE, '', $e);
        }
    }

    /**
     * 获取菜品分页信息
     * @param $brandId
     * @param $categoryId
     * @param $name
     * @param $pageSize
     * @param $pageNum
     * @param $menuId
     * @param $kind
     * @return mixed
     */
    public static function getProductDataPage($brandId, $categoryId, $name, $pageSize, $pageNum, $menuId, $kind)
    {
        return self::query()
                   ->when($name, function ($query) use ($name) {
                       if (is_numeric($name)) {
                           $query->where('id', 'like', "%{$name}%");
                       } else {
                           $query->where('name', 'like', "%{$name}%");
                       }

                   })
                   ->when($kind > 0, function ($query) use ($kind) {
                       $query->where("kind", $kind);
                   })
                   ->when($categoryId != 0, function ($query) use ($categoryId) {
                       $query->where('categoryId', '=', $categoryId);
                   })
                   ->where('shopId', 0)
//            ->where(function($query){
//                $query->where();
//            })
                   ->where(['brandId' => $brandId, 'menuId' => $menuId])
                   ->orderBy('sort')
                   ->orderBy('createdAt')
                   ->paginate($pageSize, ['*'], $pageName = 'page', $pageNum);
    }

    /**
     * 查询产品信息
     * @param $query
     * @return mixed
     */
    public static function getProductList($query)
    {
        return $query->get()->toArray();
    }

    public function productPackageRel()
    {
        return $this->hasMany(PackageProductMapping::class, 'packageId', 'id');
    }

    /**
     * 根据ID获取产品信息
     * @param $productId
     * @return mixed
     */
    public static function getProductInfoById($productId)
    {
        return Product::query()
                      ->with([
                          'productPackageRel' => function ($query) {
                              return $query->where('menuId', '=', 0)
                                           ->select(['num', 'packageId', 'id', 'productId']);
                          }
                      ])
                      ->where('id', $productId)
                      ->where('menuId', 0)
                      ->first();
    }

    /**
     * 根据 ids 返回菜品库数据
     *
     * @param array $productId
     * @return Builder[]|Collection
     */
    public static function getProductInfoByIds(array $productId, int $menuId = 0)
    {
        $list = Product::query()->whereIn('id', $productId)->where('menuId', $menuId)->get()->toArray();
        $list = array_column($list, null, 'id');
        foreach ($list as &$l) {
            $l['packageList'] = [];
        }

        $packageIdsList = [];
        foreach ($list as $one) {
            if ($one['type'] == ProductCode::PRODUCT_TYPE_PACKAGE) {
                array_push($packageIdsList, $one['id']);
            }
        }

        if (count($packageIdsList) > 0) {
            // 查询套餐关联的单品商品
            $pgSonList = PackageProductMapping::query()
                                              ->whereIn('packageId', $packageIdsList)
                                              ->where('menuId', $menuId)
                                              ->get()
                                              ->each(function ($item) {
                                                  $item['name'] = $item['productName'];
                                                  unset($item['productName']);
                                              })
                                              ->toArray();

            // 直接组合进 $list , 暂时不管价格

            $pgSonFilterList = [];
            foreach ($pgSonList as $son) {
                $productId = $son['productId'];
                if (key_exists($productId, $list)) {
                    continue;
                } else {
                    $son['id']                   = $son['productId'];
                    $pgSonFilterList[$productId] = $son;
                }
            }
            unset($son);
            $pgNewSonList = [];
            foreach ($pgSonList as $son) {
                $pgNewSonList[] = $son;
            }

            foreach ($pgNewSonList as $sonList) {
                if (key_exists($sonList['packageId'], $list)) {
                    array_push($list[$sonList['packageId']]['packageList'], $sonList);
                }
            }

            $list = array_merge($list, $pgSonFilterList);

        }

        return $list;
    }


    /**
     * 根据 ids 返回菜品库数据 - 通过 菜品 缓存数据
     *
     * @param array $productId
     * @return Builder[]|Collection
     */
    public static function getCustomProductInfoByIds(array $productId, int $shopId)
    {

    }

    /**
     * 根据产品名获取产品信息
     * @param $productId
     * @return mixed
     */
    public static function getProductInfoByName($name)
    {
        return Product::where('name', 'like', $name . "%")->first();
    }

    /**
     * 修改产品信息
     * @param $productId
     * @param $menuId
     * @param $data
     * @return mixed
     */
    public static function updateProduct($productId, $menuId, $data)
    {
        return Product::query()
                      ->where('id', $productId)
                      ->where('menuId', $menuId)
                      ->update($data);
    }

    /**
     * 批量绑定菜品的菜单
     * @param array $ids
     * @param int $menuId
     */
    public static function bindMenuIds(array $ids, int $menuId): bool
    {
        try {
            DB::connection('mysql')->beginTransaction();

            // 先把其他的取消绑定
            self::query()->where('menuId', $menuId)->whereNotIn('id', $ids)->update(['menuId' => 0]);

            // 绑定
            self::query()->whereIn('id', $ids)->update(['menuId' => 1]);

            DB::connection('mysql')->commit();
        } catch (\Exception $e) {
            DB::connection('mysql')->rollBack();

            Log::warning("BindMenuIds DB ERR: " . $e->getMessage());
            Log::warning($e);
            return false;
        }

        return true;
    }

    /**
     * 查询菜单下的菜品
     * @return Builder[]|Collection
     */
    public static function getMenuProducts(int $menuId = 0)
    {
        return Cache::remember(ProductCacheEnum::getProductList($menuId), getSwitchCacheTime(86400),
            function () use ($menuId) {
                return self::query()
                           ->with('categoryRel')
                           ->with([
                               'productPackageRel' => function ($query) use ($menuId) {
                                   return $query->where(['menuId' => $menuId])->get();
                               }
                           ])
                           ->where('menuId', $menuId)
                           ->where('kind', ProductCode::KIND_NORMAL)
                           ->where('status', DBEnum::STATUS_ON)
                           ->orderBy('sort')
                           ->get();
            });
    }

    /**
     * 刷新 - 查询自定义菜品库数据
     */
    public static function refreshGetMenuProductsCustom(): void
    {
        Cache::forget(ProductCacheEnum::getCustomPublicProductList());
//        self::getMenuProductsCustom(); // 如果立刻再生成缓存,会生成失败,暂未找到原因.
    }

    /**
     * 查询自定义菜品库数据
     * @return Builder[]|Collection
     */
    public static function getMenuProductsCustom()
    {
        return Cache::remember(ProductCacheEnum::getCustomPublicProductList(), getSwitchCacheTime(86400),
            function () {
                return self::query()
                           ->with('categoryRel')
                           ->with([
                               'productPackageRel' => function ($query) {
                                   return $query->get();
                               }
                           ])
                           ->where('status', DBEnum::STATUS_ON)
                           ->where('kind', ProductCode::KIND_CUSTOMER)
                           ->where('type', ProductCode::PRODUCT_TYPE_SINGLE)
                           ->orderBy('sort')
                           ->get();
            });
    }


    /**
     * 刷新 - 查询 门店 自定义套餐菜品
     *
     * @param int $shopId
     */
    public static function refreshGetMenuProductsPackageCustom(int $shopId): void
    {
        Cache::forget(ProductCacheEnum::getCustomProductPackageList($shopId));
//        self::getMenuProductsPackageCustom($shopId);
    }

    /**
     * 查询 门店 自定义套餐菜品
     *
     * @param int $shopId
     * @return mixed
     */
    public static function getMenuProductsPackageCustom(int $shopId)
    {
        return Cache::remember(ProductCacheEnum::getCustomProductPackageList($shopId), getSwitchCacheTime(86400),
            function () use ($shopId) {
                $package = self::query()
                               ->with('categoryRel')
                               ->with([
                                   'productPackageRel' => function ($query) {
                                       return $query->get();
                                   }
                               ])
                               ->where('status', DBEnum::STATUS_ON)
                               ->where('kind', ProductCode::KIND_CUSTOMER)
                               ->where('type', ProductCode::PRODUCT_TYPE_PACKAGE)
                               ->where('shopId', $shopId)
                               ->orderBy('sort')
                               ->get();

                return $package;
            });


    }


    /**
     * 检查productIds是否都正常
     * @param int $brandId
     * @param array $productIds
     * @return bool
     */
    public static function checkProductIds(int $brandId, array $productIds)
    {
        return self::query()
                   ->where('brandId', $brandId)
                   ->whereIn('id', $productIds)
                   ->where('menuId', 0)->count() == count($productIds);
    }


    /**
     * 检查productIds是否都正常
     * @param int $brandId
     * @param array $productIds
     * @return bool
     */
    public static function checkProductIdsGetIds(int $brandId, array $productIds)
    {
        $list = collect($productIds);


        $dbLIst = self::query()
                      ->where('brandId', $brandId)
                      ->whereIn('id', $productIds)
                      ->where('menuId', 0)
                      ->get()
                      ->pluck('id');

        $diffFrom1To2 = $list->diff($dbLIst);
        $diffFrom2To1 = $dbLIst->diff($list);

        $combinedDiffs = $diffFrom1To2->merge($diffFrom2To1)->unique();

        return $combinedDiffs->isEmpty();
    }

    /**
     * 检查productId是否正常
     * @param int $brandId
     * @param int $productId
     * @return Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public static function checkProductId(int $brandId, int $menuId, int $productId)
    {
        return self::query()
                   ->where('id', $productId)
                   ->where('brandId', $brandId)
                   ->where('menuId', $menuId)
                   ->first();
    }


    /**
     * 更新|添加套餐菜品 - 子菜品信息
     *
     * @param int $shopId
     * @param int $brandId
     * @param int $productId
     * @param array $childProducts
     * @param int $price
     * @param int $menuId
     * @throws ProductException
     */
    public static function insertOrUpdateChildProducts(
        int $shopId,
        int $brandId,
        int $productId,
        array $childProducts,
        int $price,
        int $menuId = 0
    ) {
        PackageProductMapping::query()->where('packageId', $productId)
                             ->when($menuId == 0, function ($query) use ($menuId) {
                                 $query->where('menuId', $menuId);
                             })
                             ->delete();

        $maxPrice               = 0;
        $childProductLists      = collect($childProducts);
        $productIds             = $childProductLists->pluck("productId")->toArray();
        $queryChildProductLists = Product::getChildProductLists($shopId, $brandId, $menuId, $productIds);
        if (!$queryChildProductLists || $queryChildProductLists->count() !== count($productIds)) {
            $existsIds      = $queryChildProductLists->pluck("id")->toArray();
            $errProductIds  = array_diff($productIds, $existsIds);
            $errProductName = Product::query()
                                     ->whereIn("id", $errProductIds)
                                     ->where("menuId", 0)
                                     ->get()
                                     ->implode("name", ",");
            throw new ProductException(ProductCodeEnum::ERR_CHILD_PRODUCT, "存在无效的商品 【{$errProductName}】");
        }

        $childProductData = $queryChildProductLists
            ->map(function ($product) use (
                $productId,
                $childProductLists,
                &$maxPrice,
                $menuId
            ) {
                $num      = $childProductLists->where("productId", $product->id)->first()["num"];
                $price    = ($product->productStatusRel && $product->productStatusRel->price > 0) ? $product->productStatusRel->price : $product->price;
                $maxPrice += $num * $price;
                return [
                    "menuId"      => $product->menuId,
                    "packageId"   => $productId,
                    "productId"   => $product->id,
                    "num"         => $num,
                    "productName" => $product->name,
                    "price"       => $price,
                    "unit"        => $product->unit,
                    "imageUrl"    => $product->imageUrl,
                    "categoryId"  => $product->categoryId,
                ];
            })->values()->toArray();

        if ($price > $maxPrice) {
            throw new ProductException(
                BaseCodeEnum::ERR_400000,
                vsprintf("套餐售价 %s 不能超过套餐内子菜品的原价之和 %s", [
                    (string)($price / 100),
                    (string)($maxPrice / 100)
                ]));
        }

        PackageProductMapping::query()->insert($childProductData);
    }


    public function productStatusRel(): HasOne
    {
        return $this->hasOne(ShopProductStatus::class, "productId", "id");
    }

    /**
     * 获取门店子菜品列表
     *
     * @param int $shopId
     * @param int $brandId
     * @param int $menuId
     * @param array $productIds
     * @return array|Builder[]|Collection
     */
    public static function getChildProductLists(int $shopId, int $brandId, int $menuId, array $productIds = [])
    {
        return Product::query()
                      ->when($productIds, function ($query) use ($productIds) {
                          $query->whereIn("id", $productIds);
                      })
                      ->where("type", CodeEnum::PRODUCT_TYPE_SINGLE)
                      ->where("isDeleted", 0)
                      ->where("status", DBEnum::STATUS_ON)
                      ->where(function ($query) use ($menuId) {
                          $query->where("kind", CodeEnum::KIND_CUSTOMER)
                                ->orWhere(function ($query) use ($menuId) {
                                    $query->where("kind", CodeEnum::KIND_NORMAL)->where("menuId", $menuId);
                                });
                      })
                      ->whereNotExists(function ($query) use ($shopId, $brandId) {
                          $query->select(DB::raw(1))->from("shop_product_status")
                                ->where(function ($query) {
                                    $query->where("status", DBEnum::STATUS_DOWN)
                                          ->orWhere("isDeleted", 1);
                                })
                                ->where("shopId", $shopId)
                                ->where("brandId", $brandId)
                                ->whereRaw("kf_shop_product_status.productId = kf_products.id");
                      })
                      ->with([
                          "productStatusRel" => function ($query) use ($shopId, $brandId) {
                              $query->where("shopId", $shopId)->where("brandId", $brandId);
                          }
                      ])
                      ->get();
    }


    /**
     * 指定字段更新或新增
     *
     * @param array $attributes
     * @param array $values
     * @param array $fields
     */
    public static function fieldsUpdateOrCreate(array $attributes, array $values = [], array $fields = [])
    {
        if (is_null(self::query()->where($attributes)->first())) {
            self::query()->create(array_merge($attributes, $values));
        }else{
            $values = collect($values)->only($fields);
            self::query()->where($attributes)->update($values->toArray());
        }
    }
}
